package main

import (
	"crypto/ecdsa"
	"crypto/tls"
	"crypto/x509"
	eebus_switch "eebus_verify/usecases/switch"
	"encoding/pem"
	"fmt"
	"github.com/enbility/eebus-go/api"
	"github.com/enbility/eebus-go/service"
	api2 "github.com/enbility/ship-go/api"
	"github.com/enbility/ship-go/cert"
	spineapi "github.com/enbility/spine-go/api"
	"github.com/enbility/spine-go/model"
	"log"
	"os"
	"os/signal"
	"strconv"
	"syscall"
	"time"
)

var remoteSki string

type SwitchManger struct {
	service        *service.Service
	switch_usecase *eebus_switch.SWITCH
}

func (s *SwitchManger) Run() {
	var err error
	var certificate tls.Certificate

	if len(os.Args) == 5 {
		remoteSki = os.Args[2]

		certificate, err = tls.LoadX509KeyPair(os.Args[3], os.Args[4])
		if err != nil {
			usage()
			log.Fatal(err)
		}
	} else {
		certificate, err = cert.CreateCertificate("Demo", "Demo", "DE", "Demo-Unit-01")
		if err != nil {
			log.Fatal(err)
		}

		pemdata := pem.EncodeToMemory(&pem.Block{
			Type:  "CERTIFICATE",
			Bytes: certificate.Certificate[0],
		})
		fmt.Println(string(pemdata))

		b, err := x509.MarshalECPrivateKey(certificate.PrivateKey.(*ecdsa.PrivateKey))
		if err != nil {
			log.Fatal(err)
		}
		pemdata = pem.EncodeToMemory(&pem.Block{Type: "EC PRIVATE KEY", Bytes: b})
		fmt.Println(string(pemdata))
	}

	port, err := strconv.Atoi(os.Args[1])
	if err != nil {
		usage()
		log.Fatal(err)
	}

	configuration, err := api.NewConfiguration(
		"Demo", "Demo", "HEMS", "123456789",
		model.DeviceTypeTypeEnergyManagementSystem,
		[]model.EntityTypeType{model.EntityTypeTypeCEM},
		port, certificate, time.Second*4)
	if err != nil {
		log.Fatal(err)
	}
	configuration.SetAlternateIdentifier("Demo-HEMS-123456789")

	s.service = service.NewService(configuration, s)
	s.service.SetLogging(s)

	if err = s.service.Setup(); err != nil {
		fmt.Println(err)
		return
	}
	entityLocalInterface := s.service.LocalDevice().EntityForType(model.EntityTypeTypeGeneric)
	s.switch_usecase = eebus_switch.NewSWITCH(s.service, entityLocalInterface, s.switchEventCallback)
}

// main app
func usage() {
	fmt.Println("First Run:")
	fmt.Println("  go run /cmd/hems/main.go <serverport>")
	fmt.Println()
	fmt.Println("General Usage:")
	fmt.Println("  go run /cmd/hems/main.go <serverport> <evse-ski> <crtfile> <keyfile>")
}

func (s *SwitchManger) RemoteSKIConnected(service api.ServiceInterface, ski string) {

}

func (s *SwitchManger) RemoteSKIDisconnected(service api.ServiceInterface, ski string) {

}

func (s *SwitchManger) VisibleRemoteServicesUpdated(service api.ServiceInterface, entries []api2.RemoteService) {

}

func (s *SwitchManger) ServiceShipIDUpdate(ski string, shipdID string) {

}

func (s *SwitchManger) ServicePairingDetailUpdate(ski string, detail *api2.ConnectionStateDetail) {

}

// Logging interface

func (s *SwitchManger) Trace(args ...interface{}) {
	s.print("TRACE", args...)
}

func (s *SwitchManger) Tracef(format string, args ...interface{}) {
	s.printFormat("TRACE", format, args...)
}

func (s *SwitchManger) Debug(args ...interface{}) {
	s.print("DEBUG", args...)
}

func (s *SwitchManger) Debugf(format string, args ...interface{}) {
	s.printFormat("DEBUG", format, args...)
}

func (s *SwitchManger) Info(args ...interface{}) {
	s.print("INFO ", args...)
}

func (s *SwitchManger) Infof(format string, args ...interface{}) {
	s.printFormat("INFO ", format, args...)
}

func (s *SwitchManger) Error(args ...interface{}) {
	s.print("ERROR", args...)
}

func (s *SwitchManger) Errorf(format string, args ...interface{}) {
	s.printFormat("ERROR", format, args...)
}

func (s *SwitchManger) currentTimestamp() string {
	return time.Now().Format("2006-01-02 15:04:05")
}

func (s *SwitchManger) print(msgType string, args ...interface{}) {
	value := fmt.Sprintln(args...)
	fmt.Printf("%s %s %s", s.currentTimestamp(), msgType, value)
}

func (s *SwitchManger) printFormat(msgType, format string, args ...interface{}) {
	value := fmt.Sprintf(format, args...)
	fmt.Println(s.currentTimestamp(), msgType, value)
}

func (s *SwitchManger) switchEventCallback(ski string, device spineapi.DeviceRemoteInterface, entity spineapi.EntityRemoteInterface, event api.EventType) {
	log.Println("switchEventCallback")
}

func main() {
	switchManger := SwitchManger{}
	switchManger.Run()
	// Clean exit to make sure mdns shutdown is invoked
	sig := make(chan os.Signal, 1)
	signal.Notify(sig, os.Interrupt, syscall.SIGTERM)
	<-sig
	// User exit
}
